package org.fing.edu.uy.esbadp.motor.strategies;

import java.util.List;
import java.util.logging.Level;

import org.fing.edu.uy.esbadp.core.AdpFlowInterface;
import org.fing.edu.uy.esbadp.core.AdpFlowRUT;
import org.fing.edu.uy.esbadp.core.AdpFlowTRN;
import org.fing.edu.uy.esbadp.core.ExpressionReg;
import org.fing.edu.uy.esbadp.core.compare.wsdl.OperationDiff;
import org.fing.edu.uy.esbadp.core.compare.wsdl.WsdlDiff;
import org.fing.edu.uy.esbadp.core.constants.EsbAdpMonitoringPropertyKeys;
import org.fing.edu.uy.esbadp.core.entity.DMRegisteredService;
import org.fing.edu.uy.esbadp.core.entity.GenericTreeNode;
import org.fing.edu.uy.esbadp.core.entity.PropertiesMonitoring;
import org.fing.edu.uy.esbadp.core.interfaces.IAdpStrategy;
import org.fing.edu.uy.esbadp.logger.LoggerADP;
import org.fing.edu.uy.esbadp.motor.XSLT.XSLManager;
import org.fing.edu.uy.esbadp.motor.comunication.AdmAdaptationComunication;


public class AdpStrategyChangeRequest implements IAdpStrategy{

	private static final java.util.logging.Logger logger = LoggerADP.getLogger(AdpStrategyChangeRequest.class.getSimpleName());

	/*
	 * Tree Nodes = RUT -> TRN_change -> virtualService -> TRN_inverseChange 
	 *               '-----------------> virtualService     
	 */
	@Override
	public GenericTreeNode<AdpFlowInterface> getAdpTree(DMRegisteredService service,List<DMRegisteredService> equivServices,PropertiesMonitoring properties) {
		try{
			GenericTreeNode<AdpFlowInterface> root = getRUT(properties);
			GenericTreeNode<AdpFlowInterface> TRN_change = getTRN_change(properties, new Long(service.getServiceID()));
			GenericTreeNode<AdpFlowInterface> TRN_inverseChange = getTRN_inverseChange(properties, new Long(service.getServiceID()));		
				
			GenericTreeNode<AdpFlowInterface> virtualService = AdmAdaptationComunication.getAdpNodeForInvokeVirtualService(service);		
			if (virtualService != null){
				virtualService.addChild(TRN_inverseChange);
				TRN_change.addChild(virtualService);
				root.addChild(TRN_change);	
				GenericTreeNode<AdpFlowInterface> clonedVirtualSercice = virtualService.clone() ;
				clonedVirtualSercice.getChildren().clear();
				root.addChild(clonedVirtualSercice);
				return root;
			}else{
				logger.log(Level.SEVERE, "Error in getAdpNodeForInvokeVirtualService");
				return null;
			}
		}catch(Exception ex){
			logger.log(Level.SEVERE, "Exception in AdpStrategyChangeRequest...\nSee Tarce.", ex);	
			return null;
		}
	}

	private GenericTreeNode<AdpFlowInterface> getTRN_change(PropertiesMonitoring properties, Long serviceID) {
		try {
			Object contractChange = properties.getPropertyValue(EsbAdpMonitoringPropertyKeys.contractChange);
			if (contractChange != null)
			{
				WsdlDiff diff = (WsdlDiff) contractChange;
				if(diff.getOperations().size() > 0){
					XSLManager mg = new XSLManager();
					String fileContent = mg.createXSL(diff,serviceID, false);
					if (fileContent != null){
						GenericTreeNode<AdpFlowInterface> treeNode = new GenericTreeNode<AdpFlowInterface>();
						AdpFlowInterface actionTRN = new AdpFlowTRN(fileContent,"CONT-CHANGE");
						treeNode.setData(actionTRN);
						return treeNode;
					}else{
						logger.log(Level.SEVERE, "Error in createXSL");
					}
				}				
				return null;
			}else{
				logger.log(Level.INFO, "Diff value not found or empty");	
				return null;
			}		

		} catch (Exception ex) {
			logger.log(Level.SEVERE, "Exception in AdpStrategyChangeRequest...\n StackTarce => [ {0} ]", ex);	
			return null;
		}
	}
	
	
	private GenericTreeNode<AdpFlowInterface> getTRN_inverseChange(PropertiesMonitoring properties, Long serviceID) {
		try {
			Object contractChange = properties.getPropertyValue(EsbAdpMonitoringPropertyKeys.contractChange);
			if (contractChange != null)
			{
				WsdlDiff diff = (WsdlDiff) contractChange;
				if(diff.getOperations().size() > 0){
					for (OperationDiff operation : diff.getOperations() ){
						if (operation.getModificationTypeName() == OperationDiff.Modification.RENAME){
							String temp = operation.getName();
							operation.setName(operation.getNewName()+"Response");
							operation.setNewName(temp+"Response");
						}
					}
	
					XSLManager mg = new XSLManager();
					String fileContent = mg.createXSL(diff,serviceID,true);
					if (fileContent != null){
						GenericTreeNode<AdpFlowInterface> treeNode = new GenericTreeNode<AdpFlowInterface>();
						AdpFlowInterface actionTRN = new AdpFlowTRN(fileContent,"CONT-CHANGE");
						treeNode.setData(actionTRN);
						return treeNode;
					}else{
						logger.log(Level.SEVERE, "Error in createXSL");
					}
				}				
				return null;
			}else{
				logger.log(Level.INFO, "Diff value not found or empty");	
				return null;
			}		

		} catch (Exception ex) {
			logger.log(Level.SEVERE, "Exception in AdpStrategyChangeRequest...\n StackTarce => [ {0} ]", ex);	
			return null;
		}

	}
	
	private GenericTreeNode<AdpFlowInterface> getRUT(PropertiesMonitoring properties) {
		Object contractChange = properties.getPropertyValue(EsbAdpMonitoringPropertyKeys.contractChange);
		if (contractChange != null)
		{
			GenericTreeNode<AdpFlowInterface> treeNode = new GenericTreeNode<AdpFlowInterface>();
			AdpFlowRUT actionRUT = new AdpFlowRUT();
			treeNode.setData(actionRUT);
			//default index to call direct next node, not apply TRN
			actionRUT.setDefaultIndex(1);
			
			WsdlDiff diff = (WsdlDiff) contractChange;
			for(OperationDiff op : diff.getOperations()){
				ExpressionReg expression = new ExpressionReg("body",".*<\\s*\\w*\\s*:\\s*" + op.getName() + "\\s*.*>.*");
				actionRUT.addExprReg(expression, 0);
			}
			return treeNode;
		}
		return null;
	}
	
}
